import Konva from "konva";
import { Draw } from "../../../Draw/Draw";
import { nextTick } from "../../../Utils";
import { setStageCursor } from "./stage-cursor";
import { IKonva } from "../../../Interface/IKonva";
import { setGroupDraggable } from "./group-draggable";
import { haveInterSection } from "../../../Utils/konva";
import { setGroupTransformer } from "./group-transformer";

// mouseup 事件在 click 事件之前触发
export function stageMouseUp(e: IKonva.Event, draw: Draw) {
  e.cancelBubble = true;
  // 仅支持左键框选
  if (e.evt.button !== 0) return;

  const stage = draw.getStage();
  const { insertShape, inserting, selecting } = stage.attrs;

  if (insertShape && inserting) insertHandle(draw);
  // 这里 使用 nexttick 是为了解决 selectBox 样式问题
  if (selecting) nextTick(() => selectHandle(draw));

  // 恢复默认状态
  stage.setAttrs({
    insertShapeID: null, // 取消插入元素ID
    insertShape: null, // 插入元素类型
    inserting: null, // 处于正在插入过程中
    selecting: null, // 正在框选过程中
    ssx: null, // 框选、插入的初始位置
    ssy: null, // 框选、插入的初始位置
    translateMode: null, // 平移状态
    translating: null, // 平移状态
    tpx: null, // translate pageX
    tpy: null, // translate pageY
    baseStyle: null, // konvaBox style translate
  });

  // 恢复鼠标默认状态
  setStageCursor(draw, "default");
}

// 插入元素事件
function insertHandle(draw: Draw) {
  // 将scale 转换成宽高
  const stage = draw.getStage();
  const layer = draw.getLayer();
  if (!layer) return;

  // 2. 允许所有元素的拖拽
  setGroupDraggable(draw, true);

  // 定义最小宽高（直线则理解为起终点间直线距离）
  const minSize = 50;

  const { insertShapeID, insertShape } = stage.attrs;
  const group = <Konva.Group>layer.findOne(`#${insertShapeID}`);
  if (!group) return;

  let broadcastData = null;

  // 线段特殊处理 - 判断线段两端终点是否满足一定距离
  if (group.className === "Arrow") {
    const points = (group as unknown as Konva.Line).points();
    // 广播线条
    broadcastData = {
      // 需不需要箭头
      pointerLength: group.attrs.pointerLength,
      pointerWidth: group.attrs.pointerWidth,
      // 需不需要弯曲
      tension: group.attrs.tension,
      // 是否虚线
      dash: group.attrs.dash,
      insertShape,
      id: group.id(),
      layerID: layer.id(),
      x: group.x(),
      y: group.y(),
      points,
    };
  }
  // 普通节点 - 封装的 base group
  else {
    // 如果当前节点宽高过于小，则提示插入失败
    const { width, height } = group.size();
    if (width < minSize && height < minSize) {
      draw.getMessage().warn("元素太小，无法插入");
      setGroupTransformer(draw, group);
      return draw.getCommand().executeDeleteGraph();
    }

    // 取消所有节点的选中状态
    draw.clearTransformer();
    draw.clearSelected();

    // 选中当前节点
    setGroupTransformer(draw, group);
    broadcastData = {
      width: group.width(),
      height: group.height(),
      x: group.x(),
      y: group.y(),
      id: group.id(),
      layerID: layer.id(),
      insertShape,
    };
  }

  /**
   * 插入元素协同:
   *  width height x y id insertShape
   *  需要特殊处理图片、视频、统计图、表格、公式、富文本等
   *  这里仅能处理基础图形,
   *  为了实现不同 layer 的协同，还需要将 layerID 传过去
   */
  draw.broadcast({
    type: `${insertShapeID}_insert`,
    payload: broadcastData,
  });

  // 添加历史记录
  draw.render();
}

// 框选事件
function selectHandle(draw: Draw) {
  const root = draw.getRootBox();

  // 恢复默认状态，防止闪频
  const selectBoxCss = ".konva-root-container-frame_selected";
  const selectBox = <HTMLDivElement>root.querySelector(selectBoxCss);

  /**
   * 根据框选实时位置坐标关系，实时生成位置信息
   * 框选中，需要判断 哪个元素被选中 - 实时显示
   */
  const { left, top, width, height } = selectBox.style;
  // 恢复初始位置
  selectBox.style.display = "none";
  selectBox.style.top = "0";
  selectBox.style.left = "0";
  selectBox.style.width = "0";
  selectBox.style.height = "0";
  selectBox.style.opacity = "0";

  const h = (t: string) => Number(t.replace("px", ""));

  // 这个是修复单击元素选中时，会判断选中节点，导致选中失败的BUG
  if (!h(width) || !h(height)) return;

  const posArr = [h(left), h(top), h(width), h(height)];

  triggerSelectGraph(draw, posArr);
}

/**
 * 判断元素是否被选中
 */
export function triggerSelectGraph(draw: Draw, posArr: number[]) {
  nextTick(() => {
    const [left, top, width, height] = posArr;

    // 1. 先取消节点选中状态
    draw.clearTransformer();
    draw.clearLineControl();
    draw.clearSelected();

    // 2. 获取所有的节点
    const layer = draw.getLayer();
    if (!layer) return;

    const baseShapes = draw.getKonvaGraph().getBaseGraph();

    baseShapes.forEach((node) => {
      const range = { x: left, y: top, width, height };
      const isIntersection = haveInterSection(node, range);
      if (isIntersection) {
        // 给节点添加selected状态
        node.setAttrs({ selected: true });
        // 选中节点
        setGroupTransformer(draw, node);
      }
    });
  });
}
